<#assign class = bali[0].class>
<#if bali[0].Required??><#assign Required = bali[0].Required></#if>
package ${class.enclosingElement.qualifiedName};

import bali.GenericBuilder;
import javax.inject.Singleton;
import javax.inject.Inject;
import javax.annotation.Generated;
import javax.annotation.Nullable;

/**
 * Builds an instance of ${class.qualifiedName}
 *
 * Generated ${.now} by freemarker from the ${.template_name} template,
 * because ${class.qualifiedName} is annotated with @Builder.
 */
@Generated("${.template_name}")
@Singleton
public class ${class.simpleName}Builder {
<#if class.annotationMirrors?seq_contains("@bali.PostConstruct")>
	private Builder builder;

	public <#if Required??>${Required[0]?cap_first}</#if>Builder getInstance() {
		return builder;
	}
<#else>
	private static Builder builder = new Builder();

	public static <#if Required??>${Required[0]?cap_first}</#if>Builder getInstance() {
		return builder;
	}
</#if>

	@Inject
	public ${class.simpleName}Builder(<#if class.annotationMirrors?seq_contains("@bali.PostConstruct")>${class.simpleName}PostConstruct postConstruct</#if>) {
		builder = new Builder(<#if class.annotationMirrors?seq_contains("@bali.PostConstruct")>postConstruct</#if>);
	}

<#if Required??><#list Required as x>
	public interface ${x?cap_first}Builder {
		<#if x_has_next>${Required[x_index+1]?cap_first}</#if>Builder ${x}(${x.asType()} ${x});
	}

</#list></#if>
	public static class Builder
<#if class.superclass?? && class.superclass.asElement().annotationMirrors?seq_contains("@bali.Builder")>		extends ${class.superclass}Builder.Builder</#if>
		implements GenericBuilder<#if Required??><#list Required as x>, ${x?cap_first}Builder</#list></#if>
	{
<#if class.annotationMirrors?seq_contains("@bali.PostConstruct")>
		private ${class.simpleName}PostConstruct postConstruct;

		Builder(${class.simpleName}PostConstruct postConstruct) {
			this.postConstruct = postConstruct;
		}
</#if>

<#list class.enclosedElements as x>
<#if x.kind.toString() == "FIELD">		private ${x.asType()} ${x};
</#if>
</#list>

<#if Required??><#list Required as x>		public <#if x_has_next>${Required[x_index+1]?cap_first}</#if>Builder ${x}(${x.asType()} ${x}) {
			this.${x} = ${x};
			return this;
		}
	
</#list>
</#if>

<#function isBuilt x>
<#return x.asType().kind == "DECLARED" && x.asType().asElement().annotationMirrors?seq_contains("@bali.Builder")>
</#function>

<#list class.enclosedElements as x>
<#if x.kind.toString() == "FIELD" && !x.annotationMirrors?seq_contains("@bali.Required")><#if !x.annotationMirrors?seq_contains("@bali.PackageBuilt")>		public</#if> ${class.simpleName}Builder.Builder ${x}(${x.asType()}<#if isBuilt(x)>Builder.Builder</#if> ${x}) {
			this.${x} = ${x}<#if isBuilt(x)>.build()</#if>;
			return this;
		}
	
</#if>
</#list>

		protected interface Settable <#if class.superclass?? && class.superclass.asElement().annotationMirrors?seq_contains("@bali.Builder")>extends ${class.superclass}Builder.Builder.Settable</#if> {
<#list class.enclosedElements as x>
<#if x.kind.toString() == "FIELD">			 public void ${x}(${x.asType()} ${x});
</#if>
</#list>
		}

		private static class SettableImpl extends ${class.simpleName} implements Settable {
<#assign c=class>
<#assign maxLoop=20>
<#list 1..maxLoop as ignored>
<#list c.enclosedElements as x>
<#if x.kind.toString() == "FIELD">			public void ${x}(${x.asType()} ${x}) {
				this.${x} = ${x};
			}
</#if>
</#list>
<#if c.superclass?? && c.superclass.asElement().annotationMirrors?seq_contains("@bali.Builder") && c.enclosedElements??><#assign c=c.superclass.asElement()><#else><#break></#if>
</#list>
		}

<#if class.annotationMirrors?seq_contains("@bali.PostConstruct")>
		@Nullable
</#if>
		public ${class.simpleName} build() {
			SettableImpl newObject = new SettableImpl();
			populate(newObject);
<#if class.annotationMirrors?seq_contains("@bali.PostConstruct")>
			return postConstruct.build(newObject);
<#else>
			return newObject;
</#if>
		}

		protected void populate(Settable newObject) {
<#if class.superclass?? && class.superclass.asElement().annotationMirrors?seq_contains("@bali.Builder")>			super.populate(newObject);
</#if>
<#list class.enclosedElements as x>
<#if x.kind.toString() == "FIELD">
			newObject.${x}(${x});
<#if x.asType().kind.toString() == "BOOLEAN">			${x} = false;
<#elseif x.asType().class.interfaces?seq_contains("interface javax.lang.model.type.PrimitiveType")>			${x} = 0;
<#else>			${x} = null;
</#if>
</#if>

</#list>
		}

	}
}
